package cl.tinet.trainee.dao;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;

import cl.tinet.trainee.exception.ConexionException;
import cl.tinet.trainee.model.CarroTO;
import cl.tinet.trainee.model.DetalleCarroTO;
import cl.tinet.trainee.model.ProductoTO;
import cl.tinet.trainee.model.UsuarioTO;

/**
 * 
 * @author Edgar Campos
 *
 */
public class ProductosDAOImpl implements ProductosDAO {

	/**
	 * Entidad que gestion las persistencias
	 */
	private EntityManager em;

	/**
	 * Metodo constructor de la clase
	 * @param em entidad para gestionar las persistencias
	 */
	public ProductosDAOImpl(EntityManager em) {
		this.em = em;
	}

	/**
	 * {@inheritDoc}
	 */
	@SuppressWarnings("unchecked")
	public List<ProductoTO> listarProductos(int registrosPorPagina,
			int paginaActual) throws ConexionException, NoResultException {
		try {
			Query query = em
				.createQuery("SELECT p FROM ProductoTO p where p.stock > 0");
			query.setFirstResult(paginaActual);
			query.setMaxResults(registrosPorPagina);
			return (ArrayList<ProductoTO>) query.getResultList();
		} catch (NoResultException e) {
			return null;
		} catch (Exception e) {
			throw new ConexionException(
					"Ocurrio un error al conectar a la base "
							+ "de datos, notifique al administrador");
		}

	}

	/**
	 * {@inheritDoc}
	 */
	@SuppressWarnings("unchecked")
	public List<ProductoTO> listarTodosProductos() throws ConexionException,
			NoResultException {
		try {
			Query query = em.createQuery("SELECT p FROM ProductoTO p");
			return (ArrayList<ProductoTO>) query.getResultList();
		} catch (NoResultException e) {
			return null;
		} catch (Exception e) {
			throw new ConexionException(
					"Ocurrio un error al conectar a la base "
							+ "de datos, notifique al administrador");
		}

	}

	/**
	 * {@inheritDoc}
	 */
	public int crearCarro(CarroTO carroTO) throws ConexionException {
		try {
			em.persist(carroTO);
			em.flush();
			return carroTO.getIdCarro();
		} catch (Exception e) {
			throw new ConexionException(
					"Ocurrio un error al conectar a la base "
							+ "de datos, notifique al administrador");
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public Integer obtenerIdCarro()
			throws ConexionException, NoResultException {
		try {
			Query query = em
					.createQuery("SELECT c.idCarro FROM  CarroTO c"
								+ "where c.compraFinalizada = 0");
			return (Integer) query.getResultList().get(0);
		} catch (NoResultException e) {
			return null;
		} catch (Exception e) {
			throw new ConexionException(
					"Ocurrio un error al conectar a la base "
							+ "de datos, notifique al administrador");
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public CarroTO cargarCarro(int idCarro) throws ConexionException,
			NoResultException {
		try {
			Query query = em
					.createQuery("SELECT c FROM CarroTO c"
							+ " where c.idCarro = :idCarro");
			query.setParameter("idCarro", idCarro);
			return (CarroTO) query.getResultList().get(0);
		} catch (NoResultException e) {
			return null;
		} catch (Exception e) {
			throw new ConexionException(
					"Ocurrio un error al conectar a la base "
							+ "de datos, notifique al administrador");
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public boolean agregarProducto(DetalleCarroTO detalleCarroTO)
			throws ConexionException {
		try {
			em.persist(detalleCarroTO);
			em.clear();
		} catch (Exception e) {
			throw new ConexionException(
					"Ocurrio un error al conectar a la base "
							+ "de datos, notifique al administrador");
		}
		return false;
	}

	/**
	 * {@inheritDoc}
	 */
	public void descontarStock(ProductoTO productoTO) throws ConexionException {
		try {
			em.merge(productoTO);
		} catch (Exception e) {
			throw new ConexionException(
					"Ocurrio un error al conectar a la base "
							+ "de datos, notifique al administrador");
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public void actualizarDetalle(DetalleCarroTO detalleCarroTO)
			throws ConexionException {
		try {
			em.merge(detalleCarroTO);
		} catch (Exception e) {
			throw new ConexionException(
					"Ocurrio un error al conectar a la base "
							+ "de datos, notifique al administrador");
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public void actualizarProducto(ProductoTO productoTO)
			throws ConexionException {
		try {
			em.merge(productoTO);
		} catch (Exception e) {
			throw new ConexionException(
					"Ocurrio un error al conectar a la base "
							+ "de datos, notifique al administrador");
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public void eliminarDetalle(DetalleCarroTO detalleCarroTO)
			throws ConexionException {
		try {
			em.remove(buscarDetalle(detalleCarroTO));
			em.flush();
		} catch (Exception e) {
			throw new ConexionException(
					"Ocurrio un error al conectar a la base "
							+ "de datos, notifique al administrador");
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public DetalleCarroTO buscarDetalle(DetalleCarroTO detalleCarroTO)
			throws ConexionException {
		try {
			return em.find(DetalleCarroTO.class, detalleCarroTO.getIdDetalle());

		} catch (Exception e) {
			throw new ConexionException(
					"Ocurrio un error al conectar a la base "
							+ "de datos, notifique al administrador");
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public UsuarioTO identificarUsuario(UsuarioTO usuarioTO)
			throws ConexionException, NoResultException {
		try {
			Query query = em
					.createQuery("SELECT u FROM UsuarioTO u"
							+ " where u.nombreUsuario = :nombreUsuario "
							+ "and u.pass = :pass");
			query.setParameter("nombreUsuario", usuarioTO.getNombreUsuario());
			query.setParameter("pass", usuarioTO.getPass());
			return (UsuarioTO) query.getSingleResult();
		} catch (NoResultException e) {
			return null;
		} catch (Exception e) {
			throw new ConexionException(
					"Ocurrio un error al conectar a la base "
							+ "de datos, notifique al administrador");
		}

	}

	/**
	 * {@inheritDoc}
	 */
	public boolean registrarUsuario(UsuarioTO usuarioTO)
			throws ConexionException {

		try {
			em.persist(usuarioTO);
			return true;
		} catch (Exception e) {
			throw new ConexionException(
					"Ocurrio un error al conectar a la base "
							+ "de datos, notifique al administrador");
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public boolean comprar(CarroTO carroTO) throws ConexionException {

		try {
			em.merge(carroTO);
			return true;
		} catch (Exception e) {
			throw new ConexionException(
					"Ocurrio un error al conectar a la base"
							+ "de datos, notifique al administrador");
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public UsuarioTO obtenerUsuario(UsuarioTO usuarioTO)
			throws ConexionException, NoResultException {
		try {

			Query query = em
					.createQuery("SELECT u FROM UsuarioTO u"
							+ " where u.nombreUsuario = :nombreUsuario");
			query.setParameter("nombreUsuario", usuarioTO.getNombreUsuario());

			return (UsuarioTO) query.getSingleResult();
		} catch (NoResultException e) {
			return null;
		} catch (Exception e) {
			throw new ConexionException(
					"Ocurrio un error al conectar a la base"
							+ "de datos, notifique al administrador");
		}
	}

	/**
	 * @return the em
	 */
	public EntityManager getEm() {
		return em;
	}

	/**
	 * @param em
	 *            the em to set
	 */
	public void setEm(EntityManager em) {
		this.em = em;
	}

}
